package org.aplikator.server.descriptor;

import com.google.common.base.Preconditions;
import org.aplikator.client.shared.descriptor.*;
import org.aplikator.server.Context;
import org.aplikator.server.persistence.PersisterTriggers;
import org.aplikator.server.query.QueryExpression;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class View extends ServerDescriptorBase {

    private List<QueryDescriptor> filters = new ArrayList<QueryDescriptor>();

    private List<SortDescriptor> sorts = new ArrayList<SortDescriptor>();

    private List<Function> functions = new ArrayList<Function>();

    public PersisterTriggers trigger;

    private Entity entity;

    private List<Property<? extends Serializable>> properties = new ArrayList<Property<? extends Serializable>>();


    private Form form;

    private int pageSize = DEFAULT_PAGE_SIZE;

    private static final int DEFAULT_PAGE_SIZE = 15;
    
    //private Map<String, Object> clientProperties = new HashMap<String, Object>();
    
            
    public View(Entity entity) {
        super(entity.getId().substring(entity.getId().indexOf(TYPE_DELIMITER) + 1));
        this.entity = entity;
        this.setLocalizationKey(entity.getLocalizationKey());
    }

    public View(Entity entity, String id) {
        super(entity.getId().substring(entity.getId().indexOf(TYPE_DELIMITER) + 1) + SUFFIX_DELIMITER + id);
        this.entity = entity;
        this.setLocalizationKey(entity.getLocalizationKey() + "." + id);
    }

    public View(View masterView, String id) {
        super(masterView.getId().substring(masterView.getId().indexOf(TYPE_DELIMITER) + 1)+ SUFFIX_DELIMITER + id);
        this.entity = masterView.entity;
        this.setLocalizationKey(masterView.getLocalizationKey()+"."+id);
        this.filters = masterView.filters;
        this.sorts = masterView.sorts;
        this.filters = masterView.filters;
        this.functions=masterView.functions;
        this.properties=masterView.properties;
        this.form=masterView.form;
        this.pageSize=masterView.pageSize;
    }

    public List<Property<? extends Serializable>> getProperties() {
        return properties;
    }

    public View addProperty(Property<? extends Serializable> property) {
        Preconditions.checkArgument(property!=null, "Attempted to add null property to view: "+this.entity);
        properties.add(property);
        return this;
    }

    public View addQueryDescriptor(String queryId, String queryLabel, QueryExpression queryExpression, QueryParameter... parameters){
        QueryDescriptor queryDescriptor = new QueryDescriptor(this.getId().substring(this.getId().indexOf(TYPE_DELIMITER) + 1) + SUFFIX_DELIMITER + queryId,queryLabel);
        queryDescriptor.setQueryExpression(queryExpression);
        for (QueryParameter p: parameters){
            queryDescriptor.addQueryParameter(p);
        }
        filters.add(queryDescriptor);
        return this;
    }

    public View addQueryDescriptor(QueryDescriptor queryDescriptor){
        filters.add(queryDescriptor);
        return this;
    }

    List<QueryDescriptor> getQueryDescriptors(){
        return filters;
    }

    public QueryDescriptor getQueryDescriptor(String id){
        for(QueryDescriptor desc: filters){
            if (id.equals(desc.getId())) return desc;
        }
        throw new IllegalArgumentException("QueryDescriptor "+id+" not found");
    }


    public View addSortDescriptor(String sortId, String sortLabel, SortItem... items) {
        SortDescriptor sd = new SortDescriptor(this.getId().substring(this.getId().indexOf(TYPE_DELIMITER) + 1) + SUFFIX_DELIMITER + sortId,sortLabel);
        for (SortItem it:items){
            sd.addItem(it);
        }
        sorts.add(sd);
        return this;
    }

    public View setDefaultSortProperty(Property<? extends Serializable> property){
        if (sorts.size()>0){
            throw new IllegalStateException("Default sort property can be set only once. The following sorts are already set: "+sorts);
        }
        addSortDescriptor("default", "default", SortItem.ascending(property));
        return this;
    }

    List<SortDescriptor> getSortDescriptors(){
        return sorts;
    }

    public SortDescriptor getSortDescriptor(String id){
        for(SortDescriptor desc: sorts){
            if (id.equals(desc.getId())) return desc;
        }
        throw new IllegalArgumentException("SortDescriptor "+id+" not found");
    }


    public View addFunction(Function function){
        functions.add(function);
        return this;
    }

    List<Function> getFunctions(){
        return functions;
    }

    public Entity getEntity() {
        return entity;
    }

    public int getPageSize() {
        return pageSize;
    }

    public View setPageSize(int pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    public ViewDTO getViewDTO(Context ctx) {
        ViewDTO viewDTO = new ViewDTO(this.getId(), this.getLocalizedName(ctx), this.getPageSize());
        EntityDTO ent = new EntityDTO(entity.getId(), entity.getLocalizedName(ctx));
        ent.setIndexed(entity.isIndexed());
        ent.setPrimaryKey(entity.getPrimaryKey().clientClone(ctx));
        viewDTO.setEntity(ent);
        for (Function f:this.getFunctions()){
            viewDTO.addFunction(f.getFunctionDTO(ctx));
        }
        
        for (SortDescriptor sd:this.getSortDescriptors()){
            viewDTO.addSortDescriptor(sd.getSortDescriptorDTO(ctx));
        }
        for (QueryDescriptor qd:this.getQueryDescriptors()){
            viewDTO.addQueryDescriptor(qd.getQueryDescriptorDTO(ctx));
        }
        viewDTO.setFormDescriptor(createFormDescriptor(ctx));
        return viewDTO;
    }

    private FormDTO createFormDescriptor(Context ctx) {
        Form f = getForm(ctx);
        if (f==null) {
        	throw new IllegalStateException("Form is not defined for view "+this.getId());
        }
        FormDTO retval = new FormDTO(f.getId(), f.getLocalizedName(ctx), f.isHorizontal());
        retval.setLayout(f.getLayout().getWidgetDescriptor(ctx));
        return retval;
    }


    public PersisterTriggers getPersisterTriggers() {
        if (trigger == null){
            return getEntity().getPersisterTriggers();
        }else{
            return this.trigger;
        }
    }

    public View setPersistersTriggers(PersisterTriggers triggers) {
        this.trigger = triggers;
        return this;
    }



    public Form getForm(Context context) {
        return form;
    }

    public View setForm(Form form) {
        this.form = form;
        return this;
    }

    public View form(Widget layout, boolean horizontal) {
        return setForm(Form.form(layout,  horizontal));
    }

    public View form(Widget layout) {
        return form(layout, true);
    }

    /*public void registerClientProperty(String name, Object obj) {
        this.clientProperties.put(name, obj);
    }
    
    public void deregisterClientProperty(String name) {
        this.clientProperties.remove(name);
    }

    public Set<String> getClientPropertiesKeys() {
        return this.clientProperties.keySet();
    }
    
    public Object getClientProperty(String name) {
        return this.clientProperties.get(name);
    }*/
}
